package mathive.client.panels;

import mathive.client.ClientSudokuData;
import mathive.client.GameParent;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.user.client.Random;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

public class MinemapPanel extends GameParent{

	private int MINEWIDTH = 0;
	private int MINEHEIGHT = 0;
	private int MINEAMOUNT = 0; // % of the grid filled with mines

	private final int MEDIUM_WIDTH = 15;
	private final int MEDIUM_HEIGHT = 10;

	private Grid minemapGrid;
	private int[][] minemapArray;
	private int[][] correctMinemapArray;
	private Button[][] buttonArray;
	private VerticalPanel mainPanel = new VerticalPanel();
	private HTML title;
	private ListBox sizeBox = new ListBox();
	private ListBox diffBox = new ListBox();
	private Button buildMinemapButton = new Button();
	private int timeCounter = 0;
	private TextBox timer = new TextBox();
	private Timer t;
	private final DialogBox dialogBox = new DialogBox();

	public MinemapPanel(){

		timer.setStyleName("titleText");
		timer.setEnabled(false);

		title = new HTML("<h1>Minemap</h1>");

		// Populate list with possible sizes
		sizeBox.setVisibleItemCount(1);
		sizeBox.addItem("Size");
		sizeBox.addItem("10x5");
		sizeBox.addItem("15x10");
		sizeBox.addItem("20x15");

		// Populate list with possible difficulties
		diffBox.setVisibleItemCount(1);
		diffBox.addItem("Difficulty");
		diffBox.addItem("Easy");
		diffBox.addItem("Medium");
		diffBox.addItem("Hard");

		buildMinemapButton.setText("Play!");
		mainPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);

		// Listen for mouse events on the Build Minemap button.
		buildMinemapButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {

				String size = sizeBox.getItemText(sizeBox.getSelectedIndex());
				if(size.equals("Size")){
					Window.alert("You must choose size.");
					return;					
				}
					
				MINEWIDTH = Integer.valueOf(size.substring(0, size.indexOf("x"))).intValue();
				MINEHEIGHT = Integer.valueOf(size.substring(size.indexOf("x")+1)).intValue();
				if(diffBox.getItemText(diffBox.getSelectedIndex()).equals("Difficulty")){
					Window.alert("You must choose difficulty.");
					return;
				}
				if(diffBox.getItemText(diffBox.getSelectedIndex()).equals("Easy")){
					MINEAMOUNT = 5;
				} else if(diffBox.getItemText(diffBox.getSelectedIndex()).equals("Medium")){
					MINEAMOUNT = 10;
				} else if(diffBox.getItemText(diffBox.getSelectedIndex()).equals("Hard")){
					MINEAMOUNT = 15;
				}
				buildMinemap();
			}
		});

	}

	public void initialize(){
		mainPanel.clear();		

		sizeBox.setItemSelected(0, true);
		diffBox.setItemSelected(0, true);

		mainPanel.setStyleName("minemapVerticalPanel");
		mainPanel.add(title);
		mainPanel.add(sizeBox);
		mainPanel.add(diffBox);
		mainPanel.add(buildMinemapButton);

	}

	public Widget getPanel(){
		initialize();
		return mainPanel;
	}

	public Widget getPanel(int difficulty){
		MINEWIDTH = MEDIUM_WIDTH;
		MINEHEIGHT = MEDIUM_HEIGHT;
		if(difficulty == ClientSudokuData.EASY){
			MINEAMOUNT = 5;
		} else if(difficulty == ClientSudokuData.MEDIUM){
			MINEAMOUNT = 10;
		} else if(difficulty == ClientSudokuData.HARD){
			MINEAMOUNT = 15;
		}
		buildMinemap();
		return mainPanel;
	}

	public void buildMinemap(){
		mainPanel.clear();
		mainPanel.add(title);
		
		score = 0;

		minemapGrid = new Grid(MINEHEIGHT, MINEWIDTH);
		minemapGrid.setStyleName("minemapGrid");
		minemapArray = new int[MINEHEIGHT][MINEWIDTH];
		correctMinemapArray = new int[MINEHEIGHT][MINEWIDTH];
		buttonArray = new Button[MINEHEIGHT][MINEWIDTH];

		mainPanel.add(minemapGrid);
//		mainPanel.add(timer);

		// Add contents to the grid
		int numRows = minemapGrid.getRowCount();
		int numColumns = minemapGrid.getColumnCount();

		// Fill in the array with mines
		String minemap = "";

		for(int fillRow = 0; fillRow < MINEWIDTH*MINEHEIGHT; fillRow++){
			if(Random.nextInt(101)<MINEAMOUNT){
				minemap = minemap+"1";
			} else {
				minemap = minemap+"0";
			}
		}
		int k = 0;
		for(int i = 0; i < numRows; i++){
			for(int j = 0; j < numColumns; j++){
				minemapArray[i][j] = (int) minemap.charAt(k);
				k++;
			}
		}

		correctMinemap();

		// Make buttons to press for each square
		for (int row = 0; row < numRows; row++) {
			for (int col = 0; col < numColumns; col++) {
				if(minemapArray[row][col] == 48){
					Button clearButton = new Button();
					clearButton.setStyleName("clearButton");
					clearButton.addClickHandler(new ClickHandler() {
						public void onClick(ClickEvent event) {
							checkMinemap((Button) event.getSource());
						}
					});
					minemapGrid.setWidget(row, col, clearButton);
					buttonArray[row][col] = clearButton;
				} else {
					Button mineButton = new Button();
					mineButton.setStyleName("mineButton");
					mineButton.addClickHandler(new ClickHandler() {
						public void onClick(ClickEvent event) {
							checkMinemap((Button) event.getSource());
						}
					});
					minemapGrid.setWidget(row, col, mineButton);
					buttonArray[row][col] = mineButton;
				}
			}
		}

		// Create a new timer that updates the playing time.
		t = new Timer() {
			public void run() {
				timeCounter++;
				timer.setText(Integer.toString(timeCounter));
			}
		};

		t.scheduleRepeating(1000);

	}

	private void correctMinemap(){

		int numRows = minemapGrid.getRowCount();
		int numColumns = minemapGrid.getColumnCount();

		int foundRow = 0;
		int foundCol = 0;

		// Find the position of the clicked button
		for (int row = 0; row < numRows; row++) {
			for (int col = 0; col < numColumns; col++) {
				minemapGrid.getCellFormatter().setStyleName(row, col, "minemapGridCell");
				// Check if the button is a bomb or if there are bombs around it
				if(minemapArray[row][col] == 49){
					correctMinemapArray[row][col] = -1;
				} else {
					int nearRow = row-1;
					int reduceRow = 3;
					if(row == 0){
						nearRow = 0;
						reduceRow = 2;
					}

					int nearCol = col-1;
					int reduceCol = 3;
					if(col == 0){
						nearCol = 0;
						reduceCol = 2;
					}

					int bombsNearby = 0;

					for(int checkRow = nearRow; checkRow < nearRow+reduceRow && checkRow < MINEHEIGHT; checkRow++){
						for(int checkCol = nearCol; checkCol < nearCol+reduceCol && checkCol < MINEWIDTH; checkCol++){
							if(checkRow == foundRow && checkCol == foundCol){
								// Do nothing
							} else {
								if(minemapArray[checkRow][checkCol] == 49){
									bombsNearby++;
								}
							}
						}
					}
					correctMinemapArray[row][col] = bombsNearby;
				}
			}
		}
	}

	private void checkMinemap(Button button){

		int numRows = minemapGrid.getRowCount();
		int numColumns = minemapGrid.getColumnCount();

		Boolean foundIt = false;
		int foundRow = 0;
		int foundCol = 0;

		// Find the position of the clicked button
		for (int row = 0; row < numRows; row++) {
			if(!foundIt){
				for (int col = 0; col < numColumns; col++) {
					if(!foundIt){
						if(buttonArray[row][col].equals(button)){
							foundRow = row;
							foundCol = col;
							foundIt = true;
						}
					}
				}
			}
		}

		// Check if the button is a bomb or if there are bombs around it
		if(correctMinemapArray[foundRow][foundCol] == -1){
			button.setEnabled(false);
			button.setText("X");
			button.setStyleName("clickedMineButton");
			score = 0;
			showResult("You stepped on a mine!");// after " +Integer.toString(timeCounter)+ " seconds!");
			return;
		} else if(correctMinemapArray[foundRow][foundCol] == 0){
			button.setEnabled(false);
			button.setText(" ");
			button.setStyleName("clickedClearButton");
			checkSurroundings(foundRow, foundCol);
		} else {
			button.setEnabled(false);
			button.setText(Integer.toString(correctMinemapArray[foundRow][foundCol]));
			button.setStyleName("clearButton");
		}

		if(minemapIsComplete()){
			score = 10;
			showResult("You cleared the mine field!");// after " +Integer.toString(timeCounter)+ " seconds!");
			return;
		}
	}

	private void checkSurroundings(int foundRow, int foundCol){
		int nearRow = foundRow-1;
		int reduceRow = 3;
		if(foundRow == 0){
			nearRow = 0;
			reduceRow = 2;
		}

		int nearCol = foundCol-1;
		int reduceCol = 3;
		if(foundCol == 0){
			nearCol = 0;
			reduceCol = 2;
		}

		for(int checkRow = nearRow; checkRow < nearRow+reduceRow && checkRow < MINEHEIGHT; checkRow++){
			for(int checkCol = nearCol; checkCol < nearCol+reduceCol && checkCol < MINEWIDTH; checkCol++){
				if(checkRow == foundRow && checkCol == foundCol){
					// Do nothing
				} else {
					if(correctMinemapArray[checkRow][checkCol] == 0){
						Button button = (Button) minemapGrid.getWidget(checkRow, checkCol);
						if(button.getText().isEmpty()){
							checkMinemap(button);
						}
					} else {
						Button button = (Button) minemapGrid.getWidget(checkRow, checkCol);
						button.setText(Integer.toString(correctMinemapArray[checkRow][checkCol]));
						button.setEnabled(false);
						button.setStyleName("clearButton");
					}
				}
			}
		}
	}

	private boolean minemapIsComplete(){

		boolean complete = true;

		int numRows = minemapGrid.getRowCount();
		int numColumns = minemapGrid.getColumnCount();

		// Find the position of the clicked button
		for (int row = 0; row < numRows; row++) {
			if(complete){
				for (int col = 0; col < numColumns; col++) {
					if(!buttonArray[row][col].getText().isEmpty() || buttonArray[row][col].getStyleName().contains("mineButton")){
						// Do nothing if there are unclicked buttons that are not mines
					} else{
						complete = false;
						break;
					}
				}
			}
		}

		return complete;
	}

	private void showResult(String result){

		dialogBox.clear();

		int numRows = minemapGrid.getRowCount();
		int numColumns = minemapGrid.getColumnCount();

		// Find the position of the clicked button
		for (int row = 0; row < numRows; row++) {
			for (int col = 0; col < numColumns; col++) {
				buttonArray[row][col].setEnabled(false);
			}

		}

		t.cancel();

		// Create a dialog box and set the caption text
		dialogBox.ensureDebugId("cwDialogBox");
		dialogBox.setText("Result");
		dialogBox.setStyleName("dialogBox");

		// Create a table to layout the content
		VerticalPanel dialogContents = new VerticalPanel();
		dialogContents.setSpacing(4);
		dialogBox.setWidget(dialogContents);

		// Add some text to the top of the dialog
		TextBox details = new TextBox();
		details.setText(result);
		details.setStyleName("detailsBox");
		dialogContents.add(details);
		dialogContents.setCellHorizontalAlignment(details,
				HasHorizontalAlignment.ALIGN_CENTER);

		// Add a close button at the bottom of the dialog
		Button closeButton = new Button("Close",
				new ClickHandler() {
			public void onClick(ClickEvent event) {
				dialogBox.hide();
				ResultsPanel resultsPanel = new ResultsPanel();
				resultsPanel.showResult("Minemap", null, score);
				mainPanel.clear();
				mainPanel.add(resultsPanel.getPanel());
			}
		});

		dialogContents.add(closeButton);
		if (LocaleInfo.getCurrentLocale().isRTL()) {
			dialogContents.setCellHorizontalAlignment(closeButton,
					HasHorizontalAlignment.ALIGN_LEFT);

		} else {
			dialogContents.setCellHorizontalAlignment(closeButton,
					HasHorizontalAlignment.ALIGN_RIGHT);
		}
		dialogBox.center();
		dialogBox.show();

	}
}
